#include "cdsl.h"

#define compute_hash(hsh, key, length) (__hsh_get_hash(key, length) % (hsh)->size)

static inline unsigned int __hsh_get_hash(void *key, unsigned int length)
{
    char *key_start   = (char*) key;
    char *key_end     = ((char*) key) + length;
    unsigned int hash = length;
    
    while(key_start < key_end) {
        hash = (hash<<5)^(hash>>27)^(*key_start++);
    }

    return hash;
}

static inline void __hsh_clear(struct hash_table *hsh)
{
    struct vector *it, *end;
    struct hsh_kv_pair *tmp;

    if (hsh) {
        for(it=hsh->kv_pairs, end=hsh->kv_pairs+hsh->size; it<end; it++) {
            while(!vect_empty(it)) {
                vect_pop_back(it, tmp, list);
                if (hsh->_free) {
                    hsh->_free(tmp->value.v_value);
                }
                free(tmp);
            }
        }
    }
} 

static inline int __hsh_delete_pair(struct hash_table *hsh, void *key, unsigned int length, struct hsh_kv_pair **pair)
{
    struct vector *vct = NULL;
    struct hsh_kv_pair *it = NULL;
    int result = SUCCESS;

     vct = hsh->kv_pairs+compute_hash(hsh, key, length);
     if ((result = vect_empty(vct))) {
         goto end;
     }
     for (it=vect_begin(vct, struct hsh_kv_pair, list);
          it != NULL;
          it=vect_next(vct, it, list)) {
         if (it->length != length ||
             memcmp(it->key, key, length)) {
             continue;
         }
         else {
             *pair = it;
             vect_delete(vct, it, list);
             goto end;
         }
     }
     result = FAILURE;

 end:
     return result;
}

static inline int __hsh_get_pair(struct hash_table *hsh, void *key, unsigned int length, struct hsh_kv_pair **pair)
{
    struct vector *vct = NULL;
    struct hsh_kv_pair *it = NULL;
    int result = SUCCESS;

     vct = hsh->kv_pairs+compute_hash(hsh, key, length);
     if ((result = vect_empty(vct))) {
         goto end;
     }
     for (it=vect_begin(vct, struct hsh_kv_pair, list);
         it != NULL;
         it=vect_next(vct, it, list)) {
         if (it->length != length ||
             memcmp(it->key, key, length)) {
             continue;
         }
         else {
             *pair = it;
             goto end;
         }
     }
     result = FAILURE;

 end:
     return result;
}

static inline int __hsh_next_pair(struct hash_table *hsh, int *n, struct hsh_kv_pair **pair)
{
    int result = SUCCESS;

    if (!(*pair) || !(*pair = vect_next(hsh->kv_pairs+(*n), *pair, list))) {
        for ((*n) += 1; (*n) < hsh->size && vect_empty(hsh->kv_pairs+(*n)); (*n)++)
            ;
        if ((result = ((*n) >= hsh->size))) {
            goto end;
        }
        *pair = vect_begin(hsh->kv_pairs+(*n), struct hsh_kv_pair, list);
    }

 end:
    return result;
}

static inline void __hsh_make_pair(struct hsh_kv_pair **pair, void *key, unsigned int length)
{
    *pair = (struct hsh_kv_pair*)malloc(sizeof(struct kv_pair)+sizeof(char)*length);
     
    INIT_LIST_HEAD(&(*pair)->list);
    (*pair)->length = length;
    memcpy((*pair)->key, key, length);
}

void hsh_alloc(struct hash_table **hsh, void (*_free)(void*), unsigned int size)
{
    struct vector *it, *end;

    *hsh = (struct hash_table*)malloc(sizeof(struct hash_table)+sizeof(struct vector)*size);

    (*hsh)->size = size;
    for(it=(*hsh)->kv_pairs, end=(*hsh)->kv_pairs+size; it<end; it++) {
        INIT_VECTOR(it);
    }

    (*hsh)->_free = _free;
}

void hsh_free(struct hash_table **hsh)
{
    __hsh_clear(*hsh);

    free(*hsh);
    *hsh = NULL;
}

void hsh_begin(struct hash_table *hsh, int *n, struct hsh_kv_pair **pair)
{
    *n = -1;
    *pair = NULL;
}

#define create_hsh_add_impl(func, type, member)                         \
  void func(struct hash_table *hsh, void *key, unsigned int length, type value) \
  {                                                                     \
      struct hsh_kv_pair *pair;                                         \
                                                                        \
      __hsh_make_pair(&pair, key, length);                              \
      pair->value.member = value;                                       \
                                                                        \
      vect_push_front(hsh->kv_pairs+compute_hash(hsh, key, length), &pair->list); \
  }

create_hsh_add_impl(hsh_add_void, void*, v_value)
create_hsh_add_impl(hsh_add_int, int, i_value)

#define create_hsh_get_impl(func, type, member)                         \
  int func(struct hash_table *hsh, void *key, unsigned int length, type *value) \
  {                                                                     \
      struct hsh_kv_pair *pair = NULL;                                  \
      int result = SUCCESS;                                             \
                                                                        \
      if ((result = __hsh_get_pair(hsh, key, length, &pair))) {         \
          goto end;                                                     \
      }                                                                 \
      *value = pair->value.member;                                      \
                                                                        \
  end:                                                                  \
      return result;                                                    \
  }

create_hsh_get_impl(hsh_get_void, void*, v_value)
create_hsh_get_impl(hsh_get_int, int, i_value)

#define create_hsh_delete_impl(func, type, member)                      \
  int func(struct hash_table *hsh, void *key, unsigned int length, type *value) \
  {                                                                     \
      struct hsh_kv_pair *pair = NULL;                                  \
      int result = SUCCESS;                                             \
                                                                        \
      if ((result = __hsh_delete_pair(hsh, key, length, &pair))) {      \
          goto end;                                                     \
      }                                                                 \
      *value = pair->value.member;                                      \
      free(pair);                                                       \
                                                                        \
  end:                                                                  \
      return result;                                                    \
  }

create_hsh_delete_impl(hsh_delete_void, void*, v_value)
create_hsh_delete_impl(hsh_delete_int, int, i_value)

#define create_hsh_next_impl(func, type, member)                        \
  int func(struct hash_table *hsh, int *n, struct hsh_kv_pair **pair, type *value) \
  {                                                                     \
      int result = SUCCESS;                                             \
                                                                        \
      if ((result = __hsh_next_pair(hsh, n, pair))) {                   \
          goto end;                                                     \
      }                                                                 \
      *value = (*pair)->value.member;                                   \
                                                                        \
  end:                                                                  \
      return result;                                                    \
  }

create_hsh_next_impl(hsh_next_void, void*, v_value)
create_hsh_next_impl(hsh_next_int, int, i_value)
